home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 9 / Night Owl CD-ROM (NOPV9) (Night Owl Publisher) (1993).ISO / 009a / tde221.zip / FILE.C < prev    next >
C/C++ Source or Header  |  1993-04-01  |  66KB  |  2,010 lines

  1. /*
  2.  * This file contains the file i/o stuff.  These functions get stuff from
  3.  * from the outside world into a form for TDE.  The form TDE uses is a
  4.  * double linked list.  Each node in the list points to the prev and
  5.  * the next nodes, if they exist.  Also in each node is a pointer to a
  6.  * line of text, a line length variable, and a dirty node indicator.  In
  7.  * earlier versions of TDE, a '\n' was used to terminate a line of text.
  8.  * In this version, we must keep an accurate count of characters in
  9.  * each line of text, as no character is used to terminate the line.
  10.  *
  11.  * Each file must contain at least one node.  That node is called the
  12.  * EOF node.  The EOF node terminates the double linked list for each
  13.  * file.  The EOF node has a NULL pointer in the line field, a NULL
  14.  * pointer in the next field, and an EOF in the len field.  Here's
  15.  * a crude picture of the double linked list structure:
  16.  *
  17.  *              Regular node                             EOF node
  18.  *     ---------                                 ---------
  19.  *     | prev  | ---> pointer to prev node       | prev  | ---> unknown
  20.  *     | line  | ---> "Hello world"              | line  | ---> NULL
  21.  *     | len   | ---> 11                         | len   | ---> EOF
  22.  *     | dirty | ---> TRUE | FALSE               | dirty | ---> FALSE
  23.  *     | next  | ---> pointer to next node       | next  | ---> NULL
  24.  *     ---------                                 ---------
  25.  *
  26.  * Implicitly, I am assuming that EOF is defined as (-1) in stdio.h.
  27.  *
  28.  * The load_file function is probably more complicated than expected, but
  29.  * I was trying to read chunks of text that match the disk cluster size
  30.  * and/or some multiple of the cache in the disk controller.
  31.  *
  32.  *
  33.  * New editor name:  TDE, the Thomson-Davis Editor.
  34.  * Author:           Frank Davis
  35.  * Date:             June 5, 1991, version 1.0
  36.  * Date:             July 29, 1991, version 1.1
  37.  * Date:             October 5, 1991, version 1.2
  38.  * Date:             January 20, 1992, version 1.3
  39.  * Date:             February 17, 1992, version 1.4
  40.  * Date:             April 1, 1992, version 1.5
  41.  * Date:             June 5, 1992, version 2.0
  42.  * Date:             October 31, 1992, version 2.1
  43.  * Date:             April 1, 1993, version 2.2
  44.  *
  45.  * This code is released into the public domain, Frank Davis.
  46.  * You may distribute it freely.
  47.  */
  48.  
  49.  
  50. #include "tdestr.h"             /* tde types */
  51. #include "common.h"
  52. #include "define.h"
  53. #include "tdefunc.h"
  54.  
  55.  
  56. #include <dos.h>                /* for renaming files */
  57. #include <bios.h>               /* for direct BIOS keyboard input */
  58. #include <io.h>                 /* for file attribute code */
  59. #include <fcntl.h>              /* open flags */
  60. #if defined( __MSC__ )
  61.    #include <errno.h>
  62.    #include <sys\types.h>       /* S_IWRITE etc */
  63. #endif
  64. #include <sys\stat.h>           /* S_IWRITE etc */
  65.  
  66.  
  67. /*
  68.  * Name:    hw_fattrib
  69.  * Purpose: To determine the current file attributes.
  70.  * Date:    December 26, 1991
  71.  * Passed:  name: name of file to be checked
  72.  * Returns: use the function in the tdeasm file to get the DOS file
  73.  *          attributes.  get_fattr() returns 0 or OK if no error.
  74.  */
  75. int  hw_fattrib( char *name )
  76. {
  77. register int rc;
  78. int  fattr;
  79.  
  80.    rc = get_fattr( name, &fattr );
  81.    return( rc == OK ? rc : ERROR );
  82. }
  83.  
  84.  
  85. /*
  86.  * Name:    change_mode
  87.  * Purpose: To prompt for file access mode.
  88.  * Date:    January 11, 1992
  89.  * Passed:  name:  name of file
  90.  *          line:  line to display message
  91.  * Returns: OK if file could be changed
  92.  *          ERROR otherwise
  93.  * Notes:   function is used to change file attributes for save_as function.
  94.  */
  95. int  change_mode( char *name, int line )
  96. {
  97. int  result;
  98. int  fattr;
  99. register int rc;
  100. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  101.  
  102.    rc = OK;
  103.    result = get_fattr( name, &fattr );
  104.    if (result != OK)
  105.       rc = ERROR;
  106.    else if (result == OK && fattr & READ_ONLY) {
  107.       /*
  108.        * file is read only
  109.        */
  110.       save_screen_line( 0, line, line_buff );
  111.       /*
  112.        * file is write protected. overwrite anyway (y/n)?
  113.        */
  114.       set_prompt( main6, line );
  115.       if (get_yn( ) != A_YES)
  116.          rc = ERROR;
  117.       if (rc == OK && set_fattr( name, ARCHIVE ) != OK)
  118.          rc = ERROR;
  119.       restore_screen_line( 0, line, line_buff );
  120.    }
  121.    return( rc );
  122. }
  123.  
  124.  
  125. /*
  126.  * Name:    write_file
  127.  * Purpose: To write text to a file
  128.  *           way.
  129.  * Date:    June 5, 1991
  130.  * Passed:  name:  name of disk file or device
  131.  *          open_mode:  fopen flags to be used in open
  132.  *          file:  pointer to file structure to write
  133.  *          start: first node to write
  134.  *          end:   last node to write
  135.  *          block: write a file or a marked block
  136.  * Returns: OK, or ERROR if anything went wrong
  137.  */
  138. int  write_file( char *name, int open_mode, file_infos *file, long start,
  139.                  long end, int block )
  140. {
  141. FILE *fp;       /* file to be written */
  142. char *p;
  143. char *z = "\x1a";
  144. register int rc;
  145. int  bc;
  146. int  ec;
  147. int  len;
  148. int  write_z;
  149. int  write_eol;
  150. long number;
  151. line_list_ptr ll;
  152. char *open_string;
  153. char *eol;
  154. size_t eol_count;
  155.  
  156.    write_z = mode.control_z;
  157.    switch (open_mode) {
  158.       case APPEND :
  159.          open_string = "ab";
  160.          break;
  161.       case OVERWRITE :
  162.       default :
  163.          open_string = "wb";
  164.          break;
  165.    }
  166.    switch (file->crlf) {
  167.       case BINARY   :
  168.          eol_count = 0;
  169.          eol = "";
  170.          write_z = FALSE;
  171.          break;
  172.       case CRLF   :
  173.          eol_count = 2;
  174.          eol = "\r\n";
  175.          break;
  176.       case LF     :
  177.          eol_count = 1;
  178.          eol = "\n";
  179.          break;
  180.       default     :
  181.          assert( FALSE );
  182.    }
  183.    rc = OK;
  184.    if ((fp = fopen( name, open_string )) == NULL || ceh.flag == ERROR)
  185.       rc = ERROR;
  186.    else {
  187.       ec = bc = len = 0;
  188.       ll = file->line_list;
  189.       if (block == LINE || block == BOX || block == STREAM) {
  190.          if (g_status.marked_file == NULL)
  191.             rc = ERROR;
  192.          else
  193.             file = g_status.marked_file;
  194.          if (rc != ERROR) {
  195.             ll = file->line_list;
  196.             for (number=1; number<start && ll->next != NULL; number++)
  197.                ll = ll->next;
  198.          }
  199.          if (rc != ERROR && (block == BOX || block == STREAM)) {
  200.             bc  = file->block_bc;
  201.             ec  = file->block_ec;
  202.             len = ec + 1 - bc;
  203.          }
  204.          if (rc != ERROR  &&  block == STREAM) {
  205.             if (start == end )
  206.                block = BOX;
  207.          }
  208.       } else {
  209.          for (number=1; number<start && ll->next != NULL; number++)
  210.             ll = ll->next;
  211.       }
  212.       p = g_status.line_buff;
  213.       if (rc == OK) {
  214.          if (block == BOX) {
  215.  
  216.             assert( len >= 0 );
  217.             assert( len < MAX_LINE_LENGTH );
  218.  
  219.             for (;start <= end  &&  ll->len != EOF && rc == OK; start++) {
  220.                g_status.copied = FALSE;
  221.                load_box_buff( p, ll, bc, ec, ' ' );
  222.                if (fwrite( p, sizeof( char ), len, fp ) < (unsigned)len ||
  223.                           ceh.flag == ERROR)
  224.                   rc = ERROR;
  225.                if (rc != ERROR  && fwrite( eol, sizeof( char ), eol_count, fp )
  226.                                     < eol_count || ceh.flag == ERROR)
  227.                   rc = ERROR;
  228.                ll = ll->next;
  229.                if (ll == NULL)
  230.                   rc = ERROR;
  231.             }
  232.          } else {
  233.             for (number=start; number <= end && rc == OK && ll->len != EOF;
  234.                       number++) {
  235.                g_status.copied = FALSE;
  236.                copy_line( ll );
  237.                len = g_status.line_buff_len;
  238.                if (block == STREAM) {
  239.                   if (number == start) {
  240.                      bc = bc > len ? len : bc;
  241.                      len = len - bc;
  242.  
  243.                      assert( len >= 0 );
  244.  
  245.                      memmove( p, p + bc, len );
  246.                   } else if (number == end) {
  247.                      ++ec;
  248.                      len =  ec > len ? len : ec;
  249.                   }
  250.                }
  251.  
  252.                assert( len >= 0 );
  253.                assert( len < MAX_LINE_LENGTH );
  254.  
  255.                if (fwrite( p, sizeof( char ), len, fp ) < (unsigned)len ||
  256.                        ceh.flag == ERROR)
  257.                   rc = ERROR;
  258.  
  259.                /*
  260.                 * if a Control-Z is already at EOF, don't write another one.
  261.                 */
  262.                write_eol = TRUE;
  263.                if (number == end) {
  264.                   if (file->crlf == CRLF ||  file->crlf == LF) {
  265.                      if (len > 0  &&  *(p + len - 1) == '\x1a') {
  266.                         write_eol = FALSE;
  267.                         write_z = FALSE;
  268.                      }
  269.                   }
  270.                }
  271.  
  272.                if (write_eol == TRUE  &&  rc != ERROR  &&
  273.                      fwrite( eol, sizeof( char ), eol_count, fp ) < eol_count
  274.                      || ceh.flag == ERROR)
  275.                   rc = ERROR;
  276.                ll = ll->next;
  277.                if (ll == NULL)
  278.                   rc = ERROR;
  279.             }
  280.          }
  281.          if (rc != ERROR  &&  write_z) {
  282.             if (fwrite( z, sizeof( char ), 1, fp ) < 1 || ceh.flag == ERROR)
  283.                rc = ERROR;
  284.          }
  285.          g_status.copied = FALSE;
  286.          if (ceh.flag != ERROR) {
  287.             if (fclose( fp ) != 0)
  288.                rc = ERROR;
  289.          }
  290.       }
  291.    }
  292.    return( rc );
  293. }
  294.  
  295.  
  296. /*
  297.  * Name:    hw_save
  298.  * Purpose: To save text to a file
  299.  * Date:    November 11, 1989
  300.  * Passed:  name:  name of disk file
  301.  *          file:  pointer to file structure
  302.  *          start: first character in text buffer
  303.  *          end:   last character (+1) in text buffer
  304.  *          block: type of block defined
  305.  * Returns: OK, or ERROR if anything went wrong
  306.  */
  307. int hw_save( char *name, file_infos *file, long start, long end, int block )
  308. {
  309.    return( write_file( name, OVERWRITE, file, start, end, block ) );
  310. }
  311.  
  312.  
  313. /*
  314.  * Name:    hw_append
  315.  * Purpose: To append text to a file.
  316.  * Date:    November 11, 1989
  317.  * Passed:  name:  name of disk file
  318.  *          file:  pointer to file structure
  319.  *          start: first character in text buffer
  320.  *          end:   last character (+1) in text buffer
  321.  *          block: type of defined block
  322.  * Returns: OK, or ERROR if anything went wrong
  323.  */
  324. int hw_append( char *name, file_infos *file, long start, long end, int block )
  325. {
  326.    return( write_file( name, APPEND, file, start, end, block ) );
  327. }
  328.  
  329.  
  330. /*
  331.  * Name:    load_file
  332.  * Purpose: To load a file into the array of text pointers.
  333.  * Date:    December 1, 1992
  334.  * Passed:  name:       name of disk file
  335.  *          fp:         pointer to file structure
  336.  *          file_mode:  BINARY or TEXT
  337.  *          bin_len:    if opened in BINARY mode, length of node line
  338.  * Returns: OK, or ERROR if anything went wrong
  339.  */
  340. int  load_file( char *name, file_infos *fp, int *file_mode, int bin_len )
  341. {
  342. FILE *stream;                           /* stream to read */
  343. int  rc;
  344. char buff[MAX_COLS+2];
  345. char line_buff[(MAX_COLS+2)*2];         /* buffer for char and attribute  */
  346. text_ptr l;
  347. line_list_ptr ll;
  348. line_list_ptr temp_ll;
  349. unsigned long line_count;
  350. char *e;
  351. char *residue;
  352. int  len;
  353. int  res;
  354. size_t t1, t2;
  355. int  crlf;
  356. int  prompt_line;
  357.  
  358.    /*
  359.     * initialize the counters and pointers
  360.     */
  361.    rc = OK;
  362.    len = 1;
  363.    line_count = 0;
  364.    res = 0;
  365.    residue = g_status.line_buff;
  366.    prompt_line = g_display.nlines;
  367.    fp->length  = 0;
  368.    fp->undo_count = 0;
  369.    fp->undo_top = fp->undo_bot = NULL;
  370.    fp->line_list_end = fp->line_list = NULL;
  371.    ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  372.  
  373.    if (ll != NULL) {
  374.       ll->dirty = FALSE;
  375.       ll->len   = EOF;
  376.       ll->line  = NULL;
  377.       ll->next  = ll->prev = NULL;
  378.       fp->undo_top = fp->undo_bot = ll;
  379.    }
  380.  
  381.    ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  382.  
  383.    if (ll != NULL) {
  384.       ll->dirty = FALSE;
  385.       ll->len   = EOF;
  386.       ll->line  = NULL;
  387.       ll->next  = ll->prev = NULL;
  388.       fp->line_list_end = fp->line_list = ll;
  389.    }
  390.  
  391.    if ((stream = fopen( name, "rb" )) == NULL || ceh.flag == ERROR ||
  392.          rc == ERROR) {
  393.       /*
  394.        * file not found or error loading file
  395.        */
  396.       combine_strings( buff, main7a, name, main7b );
  397.       save_screen_line( 0, prompt_line, line_buff );
  398.       set_prompt( buff, prompt_line );
  399.       getkey( );
  400.       restore_screen_line( 0, prompt_line, line_buff );
  401.       if (fp->line_list != NULL)
  402.          my_free( fp->line_list );
  403.       if (fp->undo_top != NULL)
  404.          my_free( fp->undo_top );
  405.       rc = ERROR;
  406.    } else {
  407.       if (*file_mode == BINARY) {
  408.          mode.trailing = FALSE;
  409.          crlf = BINARY;
  410.          if (bin_len < 0  ||  bin_len > READ_LENGTH)
  411.             bin_len = DEFAULT_BIN_LENGTH;
  412.          for (; rc == OK;) {
  413.             t1 = fread( g_status.line_buff, sizeof(char), bin_len, stream );
  414.             if (ferror( stream )  ||  ceh.flag == ERROR) {
  415.                combine_strings( buff, "error reading file '", name, "'" );
  416.                error( WARNING, prompt_line, buff );
  417.                rc = ERROR;
  418.             } else if (t1) {
  419.  
  420.                assert( t1 < MAX_LINE_LENGTH );
  421.  
  422.                l = (text_ptr)my_malloc( t1 * sizeof(char), &rc );
  423.                temp_ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  424.  
  425.                if (rc != ERROR) {
  426.  
  427.                   /*
  428.                    * if everything is everything, copy from io buff to
  429.                    *   dynamic mem.
  430.                    */
  431.                   if (t1 > 0)
  432.                      _fmemcpy( l, g_status.line_buff, t1 );
  433.  
  434.                   ++line_count;
  435.                   temp_ll->line = l;
  436.                   temp_ll->dirty = FALSE;
  437.                   temp_ll->len  = t1;
  438.                   insert_node( fp, ll, temp_ll );
  439.                   ll = temp_ll;
  440.                } else
  441.                   rc = show_file_2big( name, prompt_line, temp_ll, l );
  442.             } else
  443.                break;
  444.          }
  445.       } else {
  446.          crlf = LF;
  447.          for (; rc == OK;) {
  448.             t1 = fread( g_status.line_buff, sizeof(char), READ_LENGTH, stream );
  449.             if (ferror( stream )  ||  ceh.flag == ERROR) {
  450.                combine_strings( buff, "error reading file '", name, "'" );
  451.                error( WARNING, prompt_line, buff );
  452.                rc = ERROR;
  453.             } else {
  454.  
  455.                /*
  456.                 * "e" walks down io buffer 1 looking for end of lines.  "t1"
  457.                 *   keeps count of number of characters in io buffer 1.
  458.                 */
  459.                e = g_status.line_buff;
  460.                while (t1 && rc == OK) {
  461.  
  462.                   /*
  463.                    * while "t1" is not zero and "len" is less than max line length,
  464.                    *   let "e" walk down the buffer until it find <LF>.
  465.                    */
  466.                   for (; t1 && len < READ_LENGTH &&  *e != '\n'; len++, e++, t1--);
  467.  
  468.                   /*
  469.                    * if "t1" is not zero, we either found a <LF> or the line
  470.                    *   length max'd out.
  471.                    */
  472.                   if (t1  ||  len >= READ_LENGTH) {
  473.  
  474.                      if (len > 1 && *e == '\n') {
  475.                         if (len - res == 1) {
  476.                            if (*(residue + res - 1) == '\r') {
  477.                               --len;
  478.                               --res;
  479.                               crlf = CRLF;
  480.                            }
  481.                         } else {
  482.                            if (*(e - 1) == '\r') {
  483.                               --len;
  484.                               crlf = CRLF;
  485.                            }
  486.                         }
  487.                      }
  488.                      if (len > 0)
  489.                         --len;
  490.  
  491.                      assert( len >= 0 );
  492.                      assert( len < MAX_LINE_LENGTH );
  493.  
  494.                      /*
  495.                       * allocate space for relocatable array of line pointers and
  496.                       *   allocate space for the line we just read.
  497.                       */
  498.                      l = (text_ptr)my_malloc( len * sizeof(char), &rc );
  499.                      temp_ll =
  500.                        (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  501.  
  502.                      if (rc != ERROR) {
  503.  
  504.                         /*
  505.                          * if everything is everything, copy from io buff to
  506.                          *   dynamic mem.  "residue" keeps up with the beginning
  507.                          *   of line in io buffer.
  508.                          */
  509.                         if (res > 0) {
  510.  
  511.                            assert( res >= 0 );
  512.                            assert( len - res >= 0 );
  513.  
  514.                            if (res > 0)
  515.                               _fmemcpy( l, residue, res );
  516.                            if (len - res > 0)
  517.                               _fmemcpy( l + res, g_status.line_buff, len - res );
  518.                            res = 0;
  519.                         } else
  520.                            if (len > 0)
  521.                               _fmemcpy( l, residue, len );
  522.  
  523.                         ++line_count;
  524.                         temp_ll->line = l;
  525.                         temp_ll->dirty = FALSE;
  526.                         temp_ll->len  = len;
  527.                         insert_node( fp, ll, temp_ll );
  528.                         ll = temp_ll;
  529.  
  530.                         /*
  531.                          * reset io buffer pointers and counters.
  532.                          */
  533.                         len = 1;
  534.                         if (t1 == 0)
  535.                            residue = g_status.tabout_buff;
  536.                         else {
  537.                            t1--;
  538.                            residue =  t1 == 0 ? g_status.tabout_buff : ++e;
  539.                         }
  540.                      } else
  541.                         rc = show_file_2big( name, prompt_line, temp_ll, l );
  542.                   } else if (len < READ_LENGTH ) {
  543.                      if (!feof( stream ))
  544.                         res = len - 1;
  545.                   } else {
  546.                      error( WARNING, prompt_line, "FRANK: error reading file!" );
  547.                      rc = ERROR;
  548.                   }
  549.                }
  550.             }
  551.  
  552.             if (rc != OK)
  553.                break;
  554.  
  555.             /*
  556.              * we may have read all lines that end in '\n', but there may
  557.              *   be some residue after the last '\n'.  ^Z is a good example.
  558.              */
  559.             if (feof( stream )) {
  560.                if (len > 1) {
  561.                   --len;
  562.                   if (t1 == 0)
  563.                      --e;
  564.  
  565.                   assert( len >= 0 );
  566.                   assert( len < MAX_LINE_LENGTH );
  567.  
  568.                   /*
  569.                    * allocate space for relocatable array of line pointers and
  570.                    *   allocate space for the line we just read.
  571.                    */
  572.                   l = (text_ptr)my_malloc( len * sizeof(char), &rc );
  573.                   temp_ll =
  574.                        (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  575.  
  576.                   if (rc != ERROR) {
  577.  
  578.                      /*
  579.                       * if everything is everything, copy from io buff to
  580.                       *   dynamic mem.  "residue" keeps up with the beginning
  581.                       *   of line in io buffer.
  582.                       */
  583.                      if (res > 0) {
  584.  
  585.                         assert( res >= 0 );
  586.                         assert( res < MAX_LINE_LENGTH);
  587.                         assert( len - res >= 0 );
  588.                         assert( len - res < MAX_LINE_LENGTH);
  589.  
  590.                         if (res > 0 )
  591.                            _fmemcpy( l, residue, res );
  592.                         if (len - res > 0)
  593.                            _fmemcpy( l + res, g_status.line_buff, len - res );
  594.                      } else
  595.                         if (len > 0)
  596.                            _fmemcpy( l, residue, len );
  597.                      ++line_count;
  598.                      temp_ll->line = l;
  599.                      temp_ll->dirty = FALSE;
  600.                      temp_ll->len  = len;
  601.                      insert_node( fp, ll, temp_ll );
  602.                   } else
  603.                      rc = show_file_2big( name, prompt_line, temp_ll, l );
  604.                }
  605.                break;
  606.             }
  607.  
  608.             t2 = fread( g_status.tabout_buff, sizeof(char), READ_LENGTH, stream );
  609.             if (ferror( stream )  ||  ceh.flag == ERROR) {
  610.                combine_strings( buff, "error reading file '", name, "'" );
  611.                error( WARNING, prompt_line, buff );
  612.                rc = ERROR;
  613.             } else if (rc == OK) {
  614.                e = g_status.tabout_buff;
  615.                while (t2 && rc == OK) {
  616.                   for (; t2 && len < READ_LENGTH &&  *e != '\n'; len++, e++, t2--);
  617.                   if (t2  ||  len >= READ_LENGTH) {
  618.  
  619.                      if (len > 1 && *e == '\n') {
  620.                         if (len - res == 1) {
  621.                            if (*(residue + res - 1) == '\r') {
  622.                               --len;
  623.                               --res;
  624.                               crlf = CRLF;
  625.                            }
  626.                         } else {
  627.                            if (*(e - 1) == '\r') {
  628.                               --len;
  629.                               crlf = CRLF;
  630.                            }
  631.                         }
  632.                      }
  633.                      if (len > 0)
  634.                         --len;
  635.  
  636.                      assert( len >= 0 );
  637.                      assert( len < MAX_LINE_LENGTH );
  638.  
  639.                      l = (text_ptr)my_malloc( len * sizeof(char), &rc );
  640.                      temp_ll =
  641.                        (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  642.  
  643.                      if (rc != ERROR) {
  644.                         if (res > 0) {
  645.  
  646.                            assert( res >= 0 );
  647.                            assert( res < MAX_LINE_LENGTH);
  648.                            assert( len - res >= 0 );
  649.                            assert( len - res < MAX_LINE_LENGTH);
  650.  
  651.                            if (res > 0)
  652.                               _fmemcpy( l, residue, res );
  653.                            if (len - res > 0)
  654.                               _fmemcpy( l+res, g_status.tabout_buff, len - res );
  655.                            res = 0;
  656.                         } else
  657.                            if (len > 0)
  658.                               _fmemcpy( l, residue, len );
  659.  
  660.                         ++line_count;
  661.                         temp_ll->line = l;
  662.                         temp_ll->dirty = FALSE;
  663.                         temp_ll->len  = len;
  664.                         insert_node( fp, ll, temp_ll );
  665.                         ll = temp_ll;
  666.  
  667.                         len = 1;
  668.                         if (t2 == 0)
  669.                            residue = g_status.line_buff;
  670.                         else {
  671.                            t2--;
  672.                            residue =  t2 == 0 ? g_status.line_buff : ++e;
  673.                         }
  674.                      } else
  675.                         rc = show_file_2big( name, prompt_line, temp_ll, l );
  676.                   } else if (len < READ_LENGTH) {
  677.                      if (!feof( stream ))
  678.                         res = len - 1;
  679.                   } else {
  680.                      error( WARNING, prompt_line, "FRANK: error reading file!" );
  681.                      rc = ERROR;
  682.                   }
  683.                }
  684.             }
  685.  
  686.             if (rc != ERROR  &&  feof( stream )) {
  687.                if (len > 1) {
  688.                   --len;
  689.                   if (t2 == 0)
  690.                      --e;
  691.  
  692.                   assert( len >= 0 );
  693.                   assert( len < MAX_LINE_LENGTH );
  694.  
  695.                   l = (text_ptr)my_malloc( len * sizeof(char), &rc );
  696.                   temp_ll =
  697.                        (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  698.  
  699.                   if (rc != ERROR) {
  700.                      if (res > 0) {
  701.  
  702.                         assert( res >= 0 );
  703.                         assert( res < MAX_LINE_LENGTH);
  704.                         assert( len - res >= 0 );
  705.                         assert( len - res < MAX_LINE_LENGTH);
  706.  
  707.                         if (res > 0)
  708.                            _fmemcpy( l, residue, res );
  709.                         if (len - res > 0)
  710.                            _fmemcpy( l+res, g_status.tabout_buff, len - res );
  711.                      } else
  712.                         if (len > 0)
  713.                            _fmemcpy( l, residue, len );
  714.  
  715.                      ++line_count;
  716.                      temp_ll->line = l;
  717.                      temp_ll->dirty = FALSE;
  718.                      temp_ll->len  = len;
  719.                      insert_node( fp, ll, temp_ll );
  720.                   } else
  721.                      rc = show_file_2big( name, prompt_line, temp_ll, l );
  722.                }
  723.                break;
  724.             }
  725.          }
  726.          *file_mode = crlf;
  727.       }
  728.  
  729.       /*
  730.        * close the file
  731.        */
  732.       fp->length = line_count;
  733.    }
  734.    if (stream != NULL)
  735.       fclose( stream );
  736.    return( rc );
  737. }
  738.  
  739.  
  740. /*
  741.  * Name:    insert_node
  742.  * Purpose: To insert a node into a double linked list
  743.  * Date:    December 1, 1992
  744.  * Passed:  fp:  pointer to file structure that owns the double linked list
  745.  *          current: pointer to current node in double linked list
  746.  *          new:     pointer to new node to insert into double linked list
  747.  * Notes:   if the current list pointer is the last node in the list, insert
  748.  *            new code behind current node.
  749.  */
  750. void insert_node( file_infos *fp, line_list_ptr current, line_list_ptr new )
  751. {
  752.  
  753.    /*
  754.     * standard double linked list insert
  755.     */
  756.    if (current->next != NULL) {
  757.       current->next->prev = new;
  758.       new->next = current->next;
  759.       current->next = new;
  760.       new->prev = current;
  761.    /*
  762.     * if the current node is the NULL node, insert the new node behind current
  763.     */
  764.    } else {
  765.       new->next = current;
  766.       if (current->prev != NULL)
  767.          current->prev->next = new;
  768.       new->prev = current->prev;
  769.       current->prev = new;
  770.       if (new->prev == NULL)
  771.          fp->line_list = new;
  772.    }
  773. }
  774.  
  775.  
  776. /*
  777.  * Name:    show_file_2big
  778.  * Purpose: tell user we ran out of room loading file
  779.  * Date:    December 1, 1992
  780.  * Passed:  name:  name of disk file
  781.  *          line:  line to display messages
  782.  *          ll:    double linked list pointer
  783.  *          t:     text line pointer
  784.  * Returns: WARNING
  785.  * Notes:   one or both of the malloc requests overflowed the heap.  free the
  786.  *            dynamic if allocated.
  787.  */
  788. int  show_file_2big( char *name, int prompt_line, line_list_ptr ll, text_ptr t )
  789. {
  790. char buff[MAX_COLS+2];
  791.  
  792.    combine_strings( buff, main10a, name, main10b );
  793.    error( WARNING, prompt_line, buff );
  794.    if (t != NULL)
  795.       my_free( t );
  796.    if (ll != NULL)
  797.       my_free( ll );
  798.    return( WARNING );
  799. }
  800.  
  801.  
  802. /*
  803.  * Name:    backup_file
  804.  * Purpose: To make a back-up copy of current file.
  805.  * Date:    June 5, 1991
  806.  * Passed:  window:  current window pointer
  807.  */
  808. int  backup_file( WINDOW *window )
  809. {
  810. char *old_line_buff;
  811. char *old_tabout_buff;
  812. int  old_line_buff_len;
  813. int  old_tabout_buff_len;
  814. int  old_copied;
  815. int  rc;
  816. file_infos *file;
  817.  
  818.    rc = OK;
  819.    file = window->file_info;
  820.    if (file->backed_up == FALSE  &&  file->modified == TRUE) {
  821.       old_copied = g_status.copied;
  822.       old_line_buff_len = g_status.line_buff_len;
  823.       old_line_buff = calloc( MAX_LINE_LENGTH, sizeof(char) );
  824.       old_tabout_buff_len = g_status.tabout_buff_len;
  825.       old_tabout_buff = calloc( MAX_LINE_LENGTH, sizeof(char) );
  826.  
  827.       if (old_line_buff != NULL  &&  old_tabout_buff != NULL) {
  828.          memcpy( old_line_buff, g_status.line_buff, MAX_LINE_LENGTH );
  829.          memcpy( old_tabout_buff, g_status.tabout_buff, MAX_LINE_LENGTH );
  830.          if ((rc = save_backup( window )) != ERROR)
  831.             file->backed_up = TRUE;
  832.          else
  833.             rc = ERROR;
  834.          memcpy( g_status.line_buff, old_line_buff, MAX_LINE_LENGTH );
  835.          memcpy( g_status.tabout_buff, old_tabout_buff, MAX_LINE_LENGTH );
  836.          g_status.line_buff_len = old_line_buff_len;
  837.          g_status.tabout_buff_len = old_tabout_buff_len;
  838.          g_status.copied = old_copied;
  839.       } else {
  840.          error( WARNING, window->bottom_line, main4 );
  841.          rc = ERROR;
  842.       }
  843.       if (old_line_buff != NULL)
  844.          free( old_line_buff );
  845.       if (old_tabout_buff != NULL)
  846.          free( old_tabout_buff );
  847.    }
  848.    return( rc );
  849. }
  850.  
  851.  
  852. /*
  853.  * Name:    edit_file
  854.  * Purpose: To allocate space for a new file structure and set up some
  855.  *           of the relevant fields.
  856.  * Date:    June 5, 1991
  857.  * Passed:  name:  name of the file to edit
  858.  *          file_mode:  BINARY or TEXT
  859.  *          bin_length: if opened in BINARY mode, length of binary lines
  860.  * Returns: OK if file structure could be created
  861.  *          ERROR if out of memory
  862.  */
  863. int  edit_file( char *name, int file_mode, int bin_length )
  864. {
  865. int  rc;        /* return code */
  866. int  existing;
  867. int  line;
  868. int  rcol;
  869. register file_infos *file; /* file structure for file belonging to new window */
  870. file_infos *fp;
  871. long found_line;
  872. line_list_ptr ll;
  873. line_list_ptr temp_ll;
  874.  
  875.    line = g_display.nlines;
  876.    rc = OK;
  877.    /*
  878.     * allocate a file structure for the new file
  879.     */
  880.    file = (file_infos *)calloc( 1, sizeof(file_infos) );
  881.    if (file == NULL) {
  882.       error( WARNING, line, main4 );
  883.       rc = ERROR;
  884.    }
  885.    existing = FALSE;
  886.    if (rc == OK  &&  hw_fattrib( name ) == OK) {
  887.       existing = TRUE;
  888.       /*
  889.        * g_status.temp_end is set last character read in file
  890.        */
  891.  
  892.       if (g_status.command != DefineSearchAndSeize  &&
  893.           g_status.command != RepeatSearchAndSeize)
  894.          rc = load_file( name, file, &file_mode, bin_length );
  895.       else {
  896.          if (g_status.sas_defined) {
  897.             rc = load_file( name, file, &file_mode, bin_length );
  898.             if (rc != ERROR) {
  899.                found_line = 1L;
  900.                rcol = 0;
  901.                ll = search_forward( file->line_list, &found_line,
  902.                                     (size_t *)&rcol );
  903.                if (ll == NULL)
  904.                   rc = ERROR;
  905.                else {
  906.                   g_status.sas_rline = found_line;
  907.                   g_status.sas_rcol  = rcol;
  908.                   g_status.sas_ll    = ll;
  909.                }
  910.             }
  911.          } else
  912.             rc = ERROR;
  913.       }
  914.    } else {
  915.       if (ceh.flag == ERROR)
  916.          rc = ERROR;
  917.       else {
  918.          existing = FALSE;
  919.          file->length = 0l;
  920.          file->undo_top = file->undo_bot = NULL;
  921.          file->line_list_end = file->line_list = NULL;
  922.          file->undo_count = 0;
  923.          ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  924.          if (ll != NULL) {
  925.             ll->line  = NULL;
  926.             ll->next  = ll->prev = NULL;
  927.             ll->dirty = FALSE;
  928.             ll->len   = EOF;
  929.             file->undo_top = file->undo_bot = ll;
  930.          } else
  931.             rc = ERROR;
  932.  
  933.          ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  934.          if (ll != NULL) {
  935.             ll->line = NULL;
  936.             ll->next = ll->prev = NULL;
  937.             ll->dirty = FALSE;
  938.             ll->len   = EOF;
  939.             file->line_list_end = file->line_list = ll;
  940.          } else
  941.             rc = ERROR;
  942.          if (rc == ERROR) {
  943.             if (file->undo_top != NULL)
  944.                my_free( file->undo_top );
  945.             if (file->line_list != NULL)
  946.                my_free( file->line_list );
  947.          } else
  948.             if (file_mode == TEXT)
  949.                file_mode = CRLF;
  950.       }
  951.    }
  952.  
  953.    if (rc != ERROR) {
  954.       /*
  955.        * add file into list
  956.        */
  957.       file->prev = NULL;
  958.       file->next = NULL;
  959.       if (g_status.file_list == NULL)
  960.          g_status.file_list = file;
  961.       else {
  962.          fp = g_status.current_file;
  963.          file->prev = fp;
  964.          if (fp->next)
  965.             fp->next->prev = file;
  966.          file->next = fp->next;
  967.          fp->next = file;
  968.       }
  969.  
  970.       /*
  971.        * set up all the info we need to know about a file.
  972.        */
  973.  
  974.       assert( file_mode == CRLF  ||  file_mode == LF  ||  file_mode == BINARY );
  975.       assert( strlen( name ) < MAX_COLS );
  976.  
  977.       strcpy( file->file_name, name );
  978.       get_fattr( name, (int *)&file->file_attrib );
  979.       file->block_type  = NOTMARKED;
  980.       file->block_br    = file->block_er = 0l;
  981.       file->block_bc    = file->block_ec = 0;
  982.       file->ref_count   = 0;
  983.       file->modified    = FALSE;
  984.       file->backed_up   = FALSE;
  985.       file->new_file    = !existing;
  986.       file->next_letter = 'a';
  987.       file->file_no     = ++g_status.file_count;
  988.       file->crlf        = file_mode;
  989.       g_status.current_file = file;
  990.       make_backup_fname( file );
  991.    } else if (file != NULL) {
  992.       /*
  993.        * free the line pointers and linked list of line pointers.
  994.        */
  995.       ll = file->undo_top;
  996.       while (ll != NULL) {
  997.          temp_ll = ll->next;
  998.          if (ll->line != NULL)
  999.             my_free( ll->line );
  1000.          my_free( ll );
  1001.          ll = temp_ll;
  1002.       }
  1003.  
  1004.       ll = file->line_list;
  1005.       while (ll != NULL) {
  1006.          temp_ll = ll->next;
  1007.          if (ll->line != NULL)
  1008.             my_free( ll->line );
  1009.          my_free( ll );
  1010.          ll = temp_ll;
  1011.       }
  1012.  
  1013. #if defined( __MSC__ )
  1014.       _fheapmin( );
  1015. #endif
  1016.  
  1017.       free( file );
  1018.    }
  1019.    return( rc );
  1020. }
  1021.  
  1022.  
  1023. /*
  1024.  * Name:    edit_another_file
  1025.  * Purpose: Bring in another file to editor.
  1026.  * Date:    June 5, 1991
  1027.  * Passed:  window:  pointer to current window
  1028.  * Notes:   New window replaces old window.  Old window becomes invisible.
  1029.  */
  1030. int  edit_another_file( WINDOW *window )
  1031. {
  1032. char fname[MAX_COLS];           /* new name for file */
  1033. char spdrive[_MAX_DRIVE];       /* splitpath drive buff */
  1034. char spdir[_MAX_DIR];           /* splitpath dir buff */
  1035. char spname[_MAX_FNAME];        /* splitpath fname buff */
  1036. char spext[_MAX_EXT];           /* splitpath ext buff */
  1037. register WINDOW *win;           /* put window pointer in a register */
  1038. int  rc;
  1039. int  file_mode;
  1040. int  bin_length;
  1041.  
  1042.    win = window;
  1043.    entab_linebuff( );
  1044.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1045.       return( ERROR );
  1046.    /*
  1047.     * read in name, no default
  1048.     */
  1049.    fname[0] = '\0';
  1050.    /*
  1051.     * file name to edit
  1052.     */
  1053.    if ((rc = get_name( ed15, win->bottom_line, fname,
  1054.                  g_display.message_color )) == OK  &&  *fname != '\0') {
  1055.       file_mode = TEXT;
  1056.       bin_length = 0;
  1057.  
  1058.       assert( strlen( fname ) <= MAX_COLS );
  1059.  
  1060.       _splitpath( fname, spdrive, spdir, spname, spext );
  1061.       if (stricmp( spext, ".exe" ) == 0  ||  stricmp( spext, ".com" ) == 0) {
  1062.          file_mode = BINARY;
  1063.          bin_length = g_status.file_chunk;
  1064.       }
  1065.       rc = attempt_edit_display( fname, LOCAL, file_mode, bin_length );
  1066.       if (rc == OK)
  1067.          show_avail_mem( );
  1068.    }
  1069.    return( rc );
  1070. }
  1071.  
  1072.  
  1073. /*
  1074.  * Name:    edit_next_file
  1075.  * Purpose: edit next file on command line.
  1076.  * Date:    January 6, 1992
  1077.  * Passed:  window:  pointer to current window
  1078.  * Notes:   New window replaces old window.  Old window becomes invisible.
  1079.  */
  1080. int  edit_next_file( WINDOW *window )
  1081. {
  1082. char name[MAX_COLS];            /* new name for file */
  1083. char spdrive[_MAX_DRIVE];       /* splitpath drive buff */
  1084. char spdir[_MAX_DIR];           /* splitpath dir buff */
  1085. char spname[_MAX_FNAME];        /* splitpath fname buff */
  1086. char spext[_MAX_EXT];           /* splitpath ext buff */
  1087. int  file_mode;
  1088. int  bin_length;
  1089. int  i;
  1090. int  update_type;
  1091. register int rc = ERROR;
  1092. register WINDOW *win;           /* put window pointer in a register */
  1093.  
  1094.    win = window;
  1095.    update_type = win == NULL ? GLOBAL : LOCAL;
  1096.    if (g_status.arg < g_status.argc) {
  1097.       if (win != NULL) {
  1098.          entab_linebuff( );
  1099.          if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1100.             return( ERROR );
  1101.       }
  1102.  
  1103.       /*
  1104.        * while we haven't found a valid file, search thru the command
  1105.        * line path.
  1106.        * we may have an invalid file name when we finish matching all
  1107.        * files according to a pattern.  then, we need to go to the next
  1108.        * command line argument if it exists.
  1109.        */
  1110.       while (rc == ERROR && g_status.arg < g_status.argc) {
  1111.  
  1112.          /*
  1113.           * if we haven't starting searching for a file, check to see if
  1114.           * the file is a valid file name.  if no file is found, then let's
  1115.           * see if we can find according to a search pattern.
  1116.           */
  1117.          if (g_status.found_first == FALSE) {
  1118.  
  1119.             assert( strlen( g_status.argv[g_status.arg] ) < MAX_COLS );
  1120.  
  1121.             strcpy( name, g_status.argv[g_status.arg] );
  1122.             rc = get_fattr( name, &i );
  1123.  
  1124.             /*
  1125.              * a new or blank file generates a return code of 2.
  1126.              * a pattern with wild cards generates a return code of 3.
  1127.              */
  1128.             if (rc == OK || rc == 2) {
  1129.                ++g_status.arg;
  1130.                rc = OK;
  1131.  
  1132.             /*
  1133.              * if we get this far, we got an invalid path name.
  1134.              *  let's try to find a matching file name using pattern.
  1135.              */
  1136.             } else if (rc != ERROR) {
  1137.                rc = my_findfirst( &g_status.dta, name, NORMAL | READ_ONLY |
  1138.                                HIDDEN | SYSTEM | ARCHIVE );
  1139.  
  1140.                /*
  1141.                 * if we found a file using wildcard characters,
  1142.                 * set the g_status.found_first flag to true so we can
  1143.                 * find the next matching file.  we need to save the
  1144.                 * pathname stem so we know which directory we are working in.
  1145.                 */
  1146.                if (rc == OK) {
  1147.                   g_status.found_first = TRUE;
  1148.                   i = strlen( name ) - 1;
  1149.                   while (i >= 0) {
  1150.                      if (name[i] == ':' || name[i] == '\\')
  1151.                         break;
  1152.                      --i;
  1153.                   }
  1154.                   name[++i] = '\0';
  1155.  
  1156.                   assert( strlen( name ) < MAX_COLS );
  1157.  
  1158.                   strcpy( g_status.path, name );
  1159.                   strcpy( name, g_status.path );
  1160.                   strcat( name, g_status.dta.name );
  1161.                } else {
  1162.                   ++g_status.arg;
  1163.                   if (win != NULL)
  1164.                      /*
  1165.                       * invalid path or file name
  1166.                       */
  1167.                      error( WARNING, win->bottom_line, win8 );
  1168.                }
  1169.             } else if (rc == ERROR)
  1170.                ++g_status.arg;
  1171.          } else {
  1172.  
  1173.             /*
  1174.              * we already found one file with wild card characters,
  1175.              * find the next matching file.
  1176.              */
  1177.             rc = my_findnext( &g_status.dta );
  1178.             if (rc == OK) {
  1179.  
  1180.                assert( strlen( g_status.path ) + strlen( g_status.dta.name )
  1181.                            < MAX_COLS );
  1182.  
  1183.                strcpy( name, g_status.path );
  1184.                strcat( name, g_status.dta.name );
  1185.             } else {
  1186.                g_status.found_first = FALSE;
  1187.                ++g_status.arg;
  1188.             }
  1189.          }
  1190.  
  1191.          /*
  1192.           * if everything is everything so far, set up the file
  1193.           * and window structures and bring the file into the editor.
  1194.           */
  1195.          if (rc == OK) {
  1196.             file_mode = g_status.file_mode;
  1197.             bin_length = g_status.file_chunk;
  1198.  
  1199.             assert( strlen( name ) <= MAX_COLS );
  1200.  
  1201.             _splitpath( name, spdrive, spdir, spname, spext );
  1202.             if (stricmp( spext, ".exe" ) == 0 || stricmp( spext, ".com" ) == 0)
  1203.                file_mode = BINARY;
  1204.             rc = attempt_edit_display( name, update_type, file_mode, bin_length );
  1205.             if (rc == OK)
  1206.                show_avail_mem( );
  1207.          }
  1208.  
  1209.          /*
  1210.           * either there are no more matching files or we had an
  1211.           * invalid file name, set rc to ERROR and let's look at the
  1212.           * next file name or pattern on the command line.
  1213.           */
  1214.          else
  1215.             rc = ERROR;
  1216.       }
  1217.    }
  1218.    if (rc == ERROR  &&  g_status.arg >= g_status.argc  &&  win != NULL)
  1219.       /*
  1220.        * no more files to load
  1221.        */
  1222.       error( WARNING, win->bottom_line, win9 );
  1223.    return( rc );
  1224. }
  1225.  
  1226.  
  1227. /*
  1228.  * Name:    search_and_seize
  1229.  * Purpose: search files for a pattern
  1230.  * Date:    October 31, 1992
  1231.  * Passed:  window:  pointer to current window
  1232.  * Notes:   New window replaces old window.  Old window becomes invisible.
  1233.  */
  1234. int  search_and_seize( WINDOW *window )
  1235. {
  1236. char name[MAX_COLS];            /* new name for file */
  1237. char searching[MAX_COLS];       /* buffer for displaying file name */
  1238. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1239. char spdrive[_MAX_DRIVE];       /* splitpath drive buff */
  1240. char spdir[_MAX_DIR];           /* splitpath dir buff */
  1241. char spname[_MAX_FNAME];        /* splitpath fname buff */
  1242. char spext[_MAX_EXT];           /* splitpath ext buff */
  1243. int  file_mode;
  1244. int  bin_length;
  1245. int  i;
  1246. int  update_type;
  1247. char *tokens;
  1248. register int rc = ERROR;
  1249. register WINDOW *win;           /* put window pointer in a register */
  1250. int  bottom_line;
  1251.  
  1252.    win = window;
  1253.    update_type = win == NULL ? GLOBAL : LOCAL;
  1254.    if (update_type == LOCAL) {
  1255.       if (!g_status.sas_defined  ||  g_status.command == DefineSearchAndSeize) {
  1256.  
  1257.          /*
  1258.           * prompt for the search pattern and the seize path.
  1259.           *   initialize all this stuff.
  1260.           */
  1261.          *sas_bm.pattern = '\0';
  1262.          if (get_name( win16, win->bottom_line, (char *)sas_bm.pattern,
  1263.                           g_display.message_color ) == ERROR)
  1264.             return( ERROR );
  1265.          if (*sas_bm.pattern == '\0')
  1266.             return( ERROR );
  1267.          *g_status.sas_tokens = '\0';
  1268.          if (get_name( win17, win->bottom_line, g_status.sas_tokens,
  1269.                           g_display.message_color ) == ERROR)
  1270.             return( ERROR );
  1271.          i = 0;
  1272.          tokens = strtok( g_status.sas_tokens, SAS_DELIMITERS );
  1273.          while (tokens != NULL) {
  1274.             g_status.sas_arg_pointers[i++] = tokens;
  1275.             tokens = strtok( NULL, SAS_DELIMITERS );
  1276.          }
  1277.          if (i == 0)
  1278.             return( ERROR );
  1279.          g_status.sas_arg_pointers[i] = NULL;
  1280.          g_status.sas_argc = i;
  1281.          g_status.sas_arg = 0;
  1282.          g_status.sas_argv = g_status.sas_arg_pointers;
  1283.          g_status.sas_found_first = FALSE;
  1284.          g_status.sas_defined = TRUE;
  1285.          bm.search_defined = sas_bm.search_defined = OK;
  1286.          build_boyer_array( );
  1287.       }
  1288.       bottom_line = win->bottom_line;
  1289.    } else
  1290.       bottom_line = g_display.nlines;
  1291.    if (g_status.sas_defined && g_status.sas_arg < g_status.sas_argc) {
  1292.       if (win != NULL) {
  1293.          entab_linebuff( );
  1294.          un_copy_line( win->ll, win, TRUE );
  1295.       }
  1296.  
  1297.       /*
  1298.        * while we haven't found a valid file, search thru the command
  1299.        * line path.
  1300.        * we may have an invalid file name when we finish matching all
  1301.        * files according to a pattern.  then, we need to go to the next
  1302.        * command line argument if it exists.
  1303.        */
  1304.       while (rc == ERROR && g_status.sas_arg < g_status.sas_argc) {
  1305.  
  1306.          /*
  1307.           * if we haven't starting searching for a file, check to see if
  1308.           * the file is a valid file name.  if no file is found, then let's
  1309.           * see if we can find according to a search pattern.
  1310.           */
  1311.          if (g_status.sas_found_first == FALSE) {
  1312.  
  1313.             assert( strlen( g_status.sas_argv[g_status.sas_arg] ) < MAX_COLS );
  1314.  
  1315.             strcpy( name, g_status.sas_argv[g_status.sas_arg] );
  1316.             rc = get_fattr( name, &i );
  1317.  
  1318.             /*
  1319.              * a new or blank file generates a return code of 2.
  1320.              * a pattern with wild cards generates a return code of 3.
  1321.              */
  1322.             if (rc == OK || rc == 2) {
  1323.                ++g_status.sas_arg;
  1324.                rc = OK;
  1325.  
  1326.             /*
  1327.              * if we get this far, we got an invalid path name.
  1328.              *  let's try to find a matching file name using pattern.
  1329.              */
  1330.             } else if (rc != ERROR) {
  1331.                rc = my_findfirst( &g_status.sas_dta, name, NORMAL | READ_ONLY |
  1332.                                HIDDEN | SYSTEM | ARCHIVE );
  1333.  
  1334.                /*
  1335.                 * if we found a file using wildcard characters,
  1336.                 * set the g_status.sas_found_first flag to true so we can
  1337.                 * find the next matching file.  we need to save the
  1338.                 * pathname stem so we know which directory we are working in.
  1339.                 */
  1340.                if (rc == OK) {
  1341.                   g_status.sas_found_first = TRUE;
  1342.                   i = strlen( name ) - 1;
  1343.                   while (i >= 0) {
  1344.                      if (name[i] == ':' || name[i] == '\\')
  1345.                         break;
  1346.                      --i;
  1347.                   }
  1348.                   name[++i] = '\0';
  1349.  
  1350.                   assert( strlen( name ) + strlen( g_status.sas_dta.name )
  1351.                                    < MAX_COLS );
  1352.  
  1353.                   strcpy( g_status.sas_path, name );
  1354.                   strcpy( name, g_status.sas_path );
  1355.                   strcat( name, g_status.sas_dta.name );
  1356.                } else {
  1357.                   ++g_status.sas_arg;
  1358.                   if (win != NULL)
  1359.                      /*
  1360.                       * invalid path or file name
  1361.                       */
  1362.                      error( WARNING, win->bottom_line, win8 );
  1363.                }
  1364.             } else if (rc == ERROR)
  1365.                ++g_status.sas_arg;
  1366.          } else {
  1367.  
  1368.             /*
  1369.              * we already found one file with wild card characters,
  1370.              * find the next matching file.
  1371.              */
  1372.             rc = my_findnext( &g_status.sas_dta );
  1373.             if (rc == OK) {
  1374.  
  1375.                assert( strlen( g_status.sas_path ) +
  1376.                        strlen( g_status.sas_dta.name ) < MAX_COLS );
  1377.  
  1378.                strcpy( name, g_status.sas_path );
  1379.                strcat( name, g_status.sas_dta.name );
  1380.             } else {
  1381.                g_status.sas_found_first = FALSE;
  1382.                ++g_status.sas_arg;
  1383.             }
  1384.          }
  1385.  
  1386.          /*
  1387.           * if everything is everything so far, set up the file
  1388.           * and window structures and bring the file into the editor.
  1389.           */
  1390.          if (rc == OK) {
  1391.  
  1392.             assert( strlen( win19 ) + strlen( name ) < MAX_COLS );
  1393.  
  1394.             strcpy( searching, win19 );
  1395.             strcat( searching, name );
  1396.             save_screen_line( 0, bottom_line, line_buff );
  1397.             set_prompt( searching, bottom_line );
  1398.             file_mode = TEXT;
  1399.             bin_length = 0;
  1400.  
  1401.             assert( strlen( name ) <= MAX_COLS );
  1402.  
  1403.             _splitpath( name, spdrive, spdir, spname, spext );
  1404.             if (stricmp( spext, ".exe" ) == 0 || stricmp( spext, ".com" ) == 0){
  1405.                file_mode = BINARY;
  1406.                bin_length = g_status.file_chunk;
  1407.             }
  1408.             rc = attempt_edit_display( name, update_type, file_mode, bin_length );
  1409.             if (rc == OK)
  1410.                show_avail_mem( );
  1411.             restore_screen_line( 0, bottom_line, line_buff );
  1412.  
  1413.             if (rc == OK) {
  1414.                win = g_status.current_window;
  1415.                bin_offset_adjust( win, g_status.sas_rline );
  1416.                find_adjust( win, g_status.sas_ll, g_status.sas_rline,
  1417.                             g_status.sas_rcol );
  1418.                make_ruler( win );
  1419.                show_ruler( win );
  1420.                show_ruler_pointer( win );
  1421.                show_window_header( win );
  1422.                if (win->vertical)
  1423.                   show_vertical_separator( win );
  1424.                win->file_info->dirty = LOCAL;
  1425.             }
  1426.          }
  1427.  
  1428.          /*
  1429.           * either there are no more matching files or we had an
  1430.           * invalid file name, set rc to ERROR and let's look at the
  1431.           * next file name or pattern on the command line.
  1432.           */
  1433.          else
  1434.             rc = ERROR;
  1435.       }
  1436.    }
  1437.    if (rc == ERROR &&  g_status.sas_arg >= g_status.sas_argc  && win != NULL)
  1438.       /*
  1439.        * no more files to load
  1440.        */
  1441.       error( WARNING, win->bottom_line, win9 );
  1442.    return( rc );
  1443. }
  1444.  
  1445.  
  1446. /*
  1447.  * Name:    attempt_edit_display
  1448.  * Purpose: try to load then display a file
  1449.  * Date:    June 5, 1991
  1450.  * Passed:  fname:       file name to load
  1451.  *          update_type: update current window or entire screen
  1452.  *          file_mode:   BINARY or TEXT
  1453.  *          bin_len:     if opened in BINARY mode, length of binary lines
  1454.  * Notes:   When we first start the editor, we need to update the entire
  1455.  *          screen.  When we load in a new file, we only need to update
  1456.  *          the current window.
  1457.  */
  1458. int  attempt_edit_display( char *fname, int update_type, int file_mode,
  1459.                            int bin_len )
  1460. {
  1461. register int rc;
  1462. WINDOW *win;
  1463.  
  1464.    rc = edit_file( fname, file_mode, bin_len );
  1465.    if (rc != ERROR) {
  1466.       rc = initialize_window( );
  1467.       if (rc != ERROR) {
  1468.          win = g_status.current_window;
  1469.          if (update_type == LOCAL) {
  1470.             if (g_status.command != DefineSearchAndSeize &&
  1471.                         g_status.command != RepeatSearchAndSeize)
  1472.                redraw_current_window( win );
  1473.             show_file_count( g_status.file_count );
  1474.             show_window_count( g_status.window_count );
  1475.             show_avail_mem( );
  1476.          } else if (update_type == GLOBAL)
  1477.             redraw_screen( win );
  1478.          if (win->file_info->new_file) {
  1479.             g_status.command = AddLine;
  1480.             insert_newline( win );
  1481.             win->file_info->modified = FALSE;
  1482.          }
  1483.       }
  1484.    }
  1485.    return( rc );
  1486. }
  1487.  
  1488.  
  1489. /*
  1490.  * Name:    make_backup_fname
  1491.  * Purpose: add .bak to file name
  1492.  * Date:    January 6, 1992
  1493.  * Passed:  file: information allowing access to the current file
  1494.  */
  1495. void make_backup_fname( file_infos *file )
  1496. {
  1497. char name[MAX_COLS];            /* new name for file */
  1498. char *p;
  1499. int  i;
  1500. int  len;
  1501.  
  1502.    /*
  1503.     * if this is a new file then don't create a backup - can't backup
  1504.     *   a nonexisting file.
  1505.     */
  1506.    if (file->new_file)
  1507.       file->backed_up = TRUE;
  1508.  
  1509.    /*
  1510.     * find the file name extension if it exists
  1511.     */
  1512.    else {
  1513.       assert( strlen( file->file_name ) < MAX_COLS );
  1514.       strcpy( name, file->file_name );
  1515.       len = strlen( name );
  1516.       for (i=len,p=name+len; i>=0; i--) {
  1517.  
  1518.          /*
  1519.           * we found the '.' extension character.  get out
  1520.           */
  1521.          if (*p == '.')
  1522.             break;
  1523.  
  1524.          /*
  1525.           * we found the drive or directory character.  no extension so
  1526.           *  set the pointer to the end of file name string.
  1527.           */
  1528.          else if (*p == '\\' || *p == ':') {
  1529.             p = name + len;
  1530.             break;
  1531.  
  1532.          /*
  1533.           * we're at the beginning of the string - no '.', drive, or directory
  1534.           *  char was found.  set the pointer to the end of file name string.
  1535.           */
  1536.          } else if (i == 0) {
  1537.             p = name + len;
  1538.             break;
  1539.          }
  1540.          --p;
  1541.       }
  1542.       assert( strlen( name ) < MAX_COLS );
  1543.       strcpy( p, ".bak" );
  1544.       strcpy( file->backup_fname, name );
  1545.    }
  1546. }
  1547.  
  1548.  
  1549. /*
  1550.  * Name:    file_file
  1551.  * Purpose: To file the current file to disk.
  1552.  * Date:    September 17, 1991
  1553.  * Passed:  window:  pointer to current window
  1554.  */
  1555. int  file_file( WINDOW *window )
  1556. {
  1557.    if (save_file( window ) == OK)
  1558.       finish( window );
  1559.    return( OK );
  1560. }
  1561.  
  1562.  
  1563. /*
  1564.  * Name:    save_file
  1565.  * Purpose: To save the current file to disk.
  1566.  * Date:    June 5, 1991
  1567.  * Passed:  window:  pointer to current window
  1568.  * Notes:   If anything goes wrong, then the modified flag is set.
  1569.  *          If the file is saved successfully, then modified flag is
  1570.  *           cleared.
  1571.  */
  1572. int  save_file( WINDOW *window )
  1573. {
  1574. char name[MAX_COLS]; /* name of file to be saved */
  1575. register file_infos *file;
  1576. int  rc;
  1577. line_list_ptr temp_ll;
  1578.  
  1579.    entab_linebuff( );
  1580.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  1581.       return( ERROR );
  1582.    file = window->file_info;
  1583.    if (file->modified == FALSE)
  1584.       return( OK );
  1585.    /*
  1586.     * set up file name
  1587.     */
  1588.    assert( strlen( file->file_name ) < MAX_COLS );
  1589.    strcpy( name, file->file_name );
  1590.  
  1591.    /*
  1592.     * see if there was a file name - if not, then make the user
  1593.     *  supply one.
  1594.     */
  1595.    if (strlen( name ) == 0)
  1596.       rc = save_as_file( window );
  1597.    else {
  1598.       /*
  1599.        * save the file
  1600.        */
  1601.       rc = write_to_disk( window, name );
  1602.       if (rc != ERROR) {
  1603.          file->modified = FALSE;
  1604.          file->new_file = FALSE;
  1605.       }
  1606.    }
  1607.  
  1608.    /*
  1609.     * clear the dirty flags
  1610.     */
  1611.    if (rc == OK) {
  1612.       temp_ll = window->file_info->line_list;
  1613.       for (; temp_ll->len != EOF; temp_ll=temp_ll->next)
  1614.          temp_ll->dirty = FALSE;
  1615.       window->file_info->dirty = GLOBAL;
  1616.    }
  1617.    return( rc );
  1618. }
  1619.  
  1620.  
  1621. /*
  1622.  * Name:    save_backup
  1623.  * Purpose: To save a backup copy of the current file to disk.
  1624.  * Date:    June 5, 1991
  1625.  * Passed:  window:  pointer to current window
  1626.  */
  1627. int  save_backup( WINDOW *window )
  1628. {
  1629.    /*
  1630.     * set up file name
  1631.     */
  1632.    return( write_to_disk( window, window->file_info->backup_fname ) );
  1633. }
  1634.  
  1635.  
  1636. /*
  1637.  * Name:    write_to_disk
  1638.  * Purpose: To write file from memory to disk
  1639.  * Date:    June 5, 1991
  1640.  * Passed:  window:  pointer to current window
  1641.  *          fname:   file name to save on disk
  1642.  */
  1643. int  write_to_disk( WINDOW *window, char *fname )
  1644. {
  1645. char name[MAX_COLS]; /* name of file to be saved */
  1646. char status_line[MAX_COLS+2]; /* status line at top of window */
  1647. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1648. register file_infos *file;
  1649. int  rc;
  1650. int  prompt_line;
  1651. int  fattr;
  1652.  
  1653.    file = window->file_info;
  1654.    prompt_line = window->bottom_line;
  1655.  
  1656.    /*
  1657.     * set up file name
  1658.     */
  1659.    assert( strlen( fname ) < MAX_COLS );
  1660.    strcpy( name, fname );
  1661.    save_screen_line( 0, prompt_line, line_buff );
  1662.    eol_clear( 0, prompt_line, g_display.message_color );
  1663.  
  1664.    /*
  1665.     * saving
  1666.     */
  1667.    combine_strings( status_line, utils6, name, "'" );
  1668.    s_output( status_line, prompt_line, 0, g_display.message_color );
  1669.    if ((rc = hw_save( name, file, 1L, file->length, NOTMARKED )) == ERROR) {
  1670.       if (ceh.flag != ERROR) {
  1671.          if (get_fattr( name, &fattr ) == OK && fattr & READ_ONLY)
  1672.             /*
  1673.              * file is read only
  1674.              */
  1675.             combine_strings( status_line, utils7a, name, utils7b );
  1676.          else
  1677.             /*
  1678.              * cannot write to
  1679.              */
  1680.             combine_strings( status_line, utils8, name, "'" );
  1681.          error( WARNING, prompt_line, status_line );
  1682.       }
  1683.    }
  1684.    restore_screen_line( 0, prompt_line, line_buff );
  1685.    return( rc );
  1686. }
  1687.  
  1688.  
  1689. /*
  1690.  * Name:    save_as_file
  1691.  * Purpose: To save the current file to disk, but under a new name.
  1692.  * Date:    June 5, 1991
  1693.  * Passed:  window:  pointer to current window
  1694.  */
  1695. int  save_as_file( WINDOW *window )
  1696. {
  1697. char name[MAX_COLS];            /* new name for file */
  1698. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1699. int  prompt_line;
  1700. int  rc;
  1701. int  fattr;
  1702. register WINDOW *win;           /* put window pointer in a register */
  1703. line_list_ptr temp_ll;
  1704.  
  1705.    win = window;
  1706.    entab_linebuff( );
  1707.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1708.       return( ERROR );
  1709.    /*
  1710.     * read in name
  1711.     */
  1712.    prompt_line = win->bottom_line;
  1713.    save_screen_line( 0, prompt_line, line_buff );
  1714.    name[0] = '\0';
  1715.    /*
  1716.     * new file name:
  1717.     */
  1718.    if ((rc = get_name( utils9, prompt_line, name,
  1719.                        g_display.message_color )) == OK  &&  *name != '\0') {
  1720.  
  1721.        /*
  1722.         * make sure it is OK to overwrite any existing file
  1723.         */
  1724.       rc = get_fattr( name, &fattr );
  1725.       if (rc == OK) {   /* file exists */
  1726.          /*
  1727.           * overwrite existing file?
  1728.           */
  1729.          set_prompt( utils10, prompt_line );
  1730.          if (get_yn( ) != A_YES  ||  change_mode( name, prompt_line ) == ERROR)
  1731.             rc = ERROR;
  1732.       }
  1733.       if (rc != ERROR)
  1734.          rc = write_to_disk( win, name );
  1735.  
  1736.       /*
  1737.        * depending on personal taste, you may want to uncomment the next
  1738.        *  lines to clear the dirty flags.
  1739.        */
  1740. /*
  1741.  *     if (rc == OK) {
  1742.  *        temp_ll = window->file_info->line_list;
  1743.  *        for (; temp_ll->len != EOF; temp_ll=temp_ll->next)
  1744.  *           temp_ll->dirty = FALSE;
  1745.  *        window->file_info->dirty = GLOBAL;
  1746.  *     }
  1747.  */
  1748.    }
  1749.    restore_screen_line( 0, prompt_line, line_buff );
  1750.    return( rc );
  1751. }
  1752.  
  1753.  
  1754. /*
  1755.  * Name:    change_fattr
  1756.  * Purpose: To change the file attributes
  1757.  * Date:    December 31, 1991
  1758.  * Passed:  window:  pointer to current window
  1759.  */
  1760. int  change_fattr( WINDOW *window )
  1761. {
  1762. char name[MAX_COLS];            /* new name for file */
  1763. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1764. file_infos *file;
  1765. WINDOW *wp;
  1766. int  prompt_line;
  1767. register int ok;
  1768. unsigned char fattr;
  1769. char *s;
  1770. int  rc;
  1771.  
  1772.    prompt_line = window->bottom_line;
  1773.    save_screen_line( 0, prompt_line, line_buff );
  1774.    name[0] = '\0';
  1775.    /*
  1776.     * enter new file attributes
  1777.     */
  1778.    if ((ok = get_name( utils14, prompt_line, name,
  1779.                        g_display.message_color )) == OK) {
  1780.       if (*name != '\0') {
  1781.          fattr = 0;
  1782.          s = name;
  1783.  
  1784.          /*
  1785.           * yes, I know lint complains about "ok = *s++".
  1786.           */
  1787.          while (ok = *s++) {
  1788.             switch (ok) {
  1789.                case 'a' :
  1790.                case 'A' :
  1791.                   fattr |= ARCHIVE;
  1792.                   break;
  1793.                case 's' :
  1794.                case 'S' :
  1795.                   fattr |= SYSTEM;
  1796.                   break;
  1797.                case 'h' :
  1798.                case 'H' :
  1799.                   fattr |= HIDDEN;
  1800.                   break;
  1801.                case 'r' :
  1802.                case 'R' :
  1803.                   fattr |= READ_ONLY;
  1804.                   break;
  1805.                default :
  1806.                   break;
  1807.             }
  1808.          }
  1809.          file = window->file_info;
  1810.          if (set_fattr( file->file_name, fattr ))
  1811.             /*
  1812.              * new file attributes not set
  1813.              */
  1814.             error( WARNING, prompt_line, utils15 );
  1815.          else {
  1816.             file->file_attrib = fattr;
  1817.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next) {
  1818.                if (wp->file_info == file && wp->visible)
  1819.                   show_window_fname( wp );
  1820.             }
  1821.          }
  1822.       }
  1823.       rc = OK;
  1824.    } else
  1825.       rc = ERROR;
  1826.    restore_screen_line( 0, prompt_line, line_buff );
  1827.    return( rc );
  1828. }
  1829.  
  1830.  
  1831. /*
  1832.  * Name:    get_fattr
  1833.  * Purpose: To get dos file attributes
  1834.  * Date:    December 26, 1991
  1835.  * Passed:  fname: ASCIIZ file name.  Null terminated file name
  1836.  *          fattr: pointer to file attributes
  1837.  * Returns: 0 if successfull, non zero if not
  1838.  * Notes:   Uses the DOS function to get file attributes.  I really didn't
  1839.  *           like the file attribute functions in the C library:  fstat() and
  1840.  *           stat() or access() and chmod().
  1841.  *           FYI, File Attributes:
  1842.  *              0x00 = Normal.  Can be read or written w/o restriction
  1843.  *              0x01 = Read-only.  Cannot be opened for write; a file with
  1844.  *                     the same name cannot be created.
  1845.  *              0x02 = Hidden.  Not found by directory search.
  1846.  *              0x04 = System.  Not found by directory search.
  1847.  *              0x08 = Volumn Label.
  1848.  *              0x10 = Directory.
  1849.  *              0x20 = Archive.  Set whenever the file is changed, or
  1850.  *                     cleared by the Backup command.
  1851.  *           Return codes:
  1852.  *              0 = No error
  1853.  *              1 = AL not 0 or 1
  1854.  *              2 = file is invalid or does not exist
  1855.  *              3 = path is invalid or does not exist
  1856.  *              5 = Access denied
  1857.  */
  1858. int  get_fattr( char far *fname, int *fattr )
  1859. {
  1860. int  rc;                /* return code */
  1861. int  attr;
  1862.  
  1863.    ASSEMBLE {
  1864.         push    ds
  1865.         mov     dx, WORD PTR fname      /* get OFFSET of filename string */
  1866.         mov     ax, WORD PTR fname+2    /* get SEGMENT of filename string */
  1867.         mov     ds, ax                  /* put SEGMENT in ds */
  1868.         mov     ax, 0x4300              /* function:  get file attributes */
  1869.         int     0x21                    /* DOS interrupt */
  1870.         pop     ds
  1871.  
  1872.         jc      an_error                /* save the error code from get attr */
  1873.         xor     ax, ax                  /* if no carry, no error */
  1874.         jmp     SHORT get_out           /* lets get out */
  1875.    }
  1876. an_error:
  1877.  
  1878.  
  1879.    ASSEMBLE {
  1880.         xor     cx, cx                  /* if error, then zero out cx - attrs */
  1881.    }
  1882. get_out:
  1883.  
  1884.    ASSEMBLE {
  1885.         mov     WORD PTR rc, ax         /* ax contains error number on error */
  1886.         mov     WORD PTR attr, cx       /* cx contains file attributes */
  1887.    }
  1888.    *fattr = attr;
  1889.    if (ceh.flag == ERROR)
  1890.       rc = ERROR;
  1891.    return( rc );
  1892. }
  1893.  
  1894.  
  1895. /*
  1896.  * Name:    set_fattr
  1897.  * Purpose: To set dos file attributes
  1898.  * Date:    December 26, 1991
  1899.  * Passed:  fname: ASCIIZ file name.  Null terminated file name
  1900.  *          fattr: file attributes
  1901.  * Returns: 0 if successfull, non zero if not
  1902.  * Notes:   Uses the DOS function to get file attributes.
  1903.  *           Return codes:
  1904.  *              0 = No error
  1905.  *              1 = AL not 0 or 1
  1906.  *              2 = file is invalid or does not exist
  1907.  *              3 = path is invalid or does not exist
  1908.  *              5 = Access denied
  1909.  */
  1910. int  set_fattr( char far *fname, int fattr )
  1911. {
  1912. int  rc;                /* return code */
  1913.  
  1914.    ASSEMBLE {
  1915.         push    ds
  1916.         mov     dx, WORD PTR fname      /* get OFFSET of filename string */
  1917.         mov     ax, WORD PTR fname+2    /* get SEGMENT of filename string */
  1918.         mov     ds, ax                  /* put SEGMENT in ds */
  1919.         mov     cx, WORD PTR fattr      /* cx contains file attributes */
  1920.         mov     ax, 0x4301              /* function:  get file attributes */
  1921.         int     0x21                    /* DOS interrupt */
  1922.         pop     ds
  1923.  
  1924.         jc      get_out                 /* save the error code from get attr */
  1925.         xor     ax, ax                  /* if no carry, no error */
  1926.    }
  1927. get_out:
  1928.  
  1929.    ASSEMBLE {
  1930.         mov     WORD PTR rc, ax         /* ax contains error number on error */
  1931.    }
  1932.    if (ceh.flag == ERROR)
  1933.       rc = ERROR;
  1934.    return( rc );
  1935. }
  1936.  
  1937.  
  1938. /*
  1939.  * Name:    get_current_directory
  1940.  * Purpose: get current directory
  1941.  * Date:    February 13, 1992
  1942.  * Passed:  path:  pointer to buffer to store path
  1943.  *          drive: drive to get current directory
  1944.  * Notes:   use simple DOS interrupt
  1945.  */
  1946. int  get_current_directory( char far *path, int drive )
  1947. {
  1948. int  rc;
  1949.  
  1950.    ASSEMBLE {
  1951.         push    si                      /* save register vars if any */
  1952.         push    ds                      /* save ds */
  1953.  
  1954.         mov     dx, WORD PTR drive      /* dl = drive, 0 = default, 1 = a, etc.. */
  1955.         mov     si, WORD PTR path       /* get OFFSET of path */
  1956.         mov     ax, WORD PTR path+2     /* get SEGMENT of path */
  1957.         mov     ds, ax                  /* put it in ds */
  1958.         mov     ah, 0x47                /* function 0x47 == get current dir */
  1959.         int     0x21                    /* standard DOS interrupt */
  1960.         xor     ax, ax                  /* zero out ax, return OK if no error */
  1961.         jnc     no_error                /* if carry set, then an error */
  1962.         mov     ax, ERROR               /* return -1 if error */
  1963.    }
  1964. no_error:
  1965.  
  1966.    ASSEMBLE {
  1967.         pop     ds                      /* get back ds */
  1968.         pop     si                      /* get back si */
  1969.         mov     WORD PTR rc, ax         /* save return code */
  1970.    }
  1971.    if (ceh.flag == ERROR)
  1972.       rc = ERROR;
  1973.    return( rc );
  1974. }
  1975.  
  1976.  
  1977. /*
  1978.  * Name:    set_current_directory
  1979.  * Purpose: set current directory
  1980.  * Date:    February 13, 1992
  1981.  * Passed:  new_path: directory path, which may include drive letter
  1982.  * Notes:   use simple DOS interrupt
  1983.  */
  1984. int  set_current_directory( char far *new_path )
  1985. {
  1986. int  rc;
  1987.  
  1988.    ASSEMBLE {
  1989.         push    ds                      /* save ds */
  1990.  
  1991.         mov     dx, WORD PTR new_path   /* get OFFSET of new_path */
  1992.         mov     ax, WORD PTR new_path+2 /* get SEGMENT of new_path */
  1993.         mov     ds, ax                  /* put it in ds */
  1994.         mov     ah, 0x3b                /* function 0x3b == set current dir */
  1995.         int     0x21                    /* standard DOS interrupt */
  1996.         xor     ax, ax                  /* zero out ax, return OK if no error */
  1997.         jnc     no_error                /* if carry set, then an error */
  1998.         mov     ax, ERROR               /* return -1 if error */
  1999.    }
  2000. no_error:
  2001.  
  2002.    ASSEMBLE {
  2003.         pop     ds                      /* get back ds */
  2004.         mov     WORD PTR rc, ax         /* save return code */
  2005.    }
  2006.    if (ceh.flag == ERROR)
  2007.       rc = ERROR;
  2008.    return( rc );
  2009. }
  2010.